﻿/* Copyright 2011 Teun Duynstee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using MongoDB.Bson;

namespace MongoAspnetProviders
{
    public class RoleProvider : System.Web.Security.RoleProvider
    {
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            foreach (var user in usernames)
            {
                AddRolesToUser(user, roleNames);
            }

        }

        private void AddRolesToUser(string user, string[] roleNames)
        {
            UpdateDocument upd = new UpdateDocument(
                new BsonElement("$pushAll", 
                    new BsonDocument(new BsonElement("Roles", new BsonArray((IEnumerable<string>)roleNames)))
                    )
                );
            QueryDocument qd = new QueryDocument(
                new BsonElement("_id", BsonString.Create(user))
                );
            _userRoleCollection.Update(qd, upd, UpdateFlags.Upsert);
        }


        public override string ApplicationName
        {
            get;set;
        }

        public override void CreateRole(string roleName)
        {
            Role r = new Role() { Name = roleName };
            RoleCollection.Save(r);
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            if (throwOnPopulatedRole)
            {
                throw new NotImplementedException();
            }
            var result = RoleCollection.Remove(new QueryDocument(
                new BsonElement("_id", BsonString.Create(roleName))
                ));
            return result.DocumentsAffected >= 0;
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();
        }

        public override string[] GetAllRoles()
        {
            IList<Role> roles = RoleCollection.Find(new QueryDocument());
            return roles.Select(r => r.Name).ToArray();
        }

        public override string[] GetRolesForUser(string username)
        {
            UserRoles user = UserRoleCollection.FindOne(new QueryDocument(
                new BsonElement("_id", BsonString.Create(username))
                ));
            return user.Roles;
        }

        public override string[] GetUsersInRole(string roleName)
        {
            IList<UserRoles> users = UserRoleCollection.Find(new QueryDocument(
                new BsonElement("Roles", BsonString.Create(roleName))
                ));
            return users.Select(u=>u.UserName).ToArray();
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            return GetRolesForUser(username).Contains(roleName);
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override bool RoleExists(string roleName)
        {
            return GetAllRoles().Contains(roleName);
        }

        public string ConnectionString { get; protected set; }


        IStoreWrapper<Role> _roleCollection;
        protected virtual IStoreWrapper<Role> RoleCollection
        {
            get
            {
                if (_roleCollection == null)
                {
                    MongoDatabase db = MongoDatabase.Create(this.ConnectionString);
                    MongoCollection<Role> collection = db.GetCollection<Role>("role");
                    DoCollectionInitialization(collection);
                    _roleCollection = new DefaultStoreWrapper<Role>(collection);
                }
                return _roleCollection;
            }
            set
            {
                _roleCollection = value;
            }
        }
        private void DoCollectionInitialization(MongoCollection<Role> collection)
        {
            //collection.EnsureIndex(""
        }
        IStoreWrapper<UserRoles> _userRoleCollection;
        protected virtual IStoreWrapper<UserRoles> UserRoleCollection
        {
            get
            {
                if (_userRoleCollection == null)
                {
                    MongoDatabase db = MongoDatabase.Create(this.ConnectionString);
                    MongoCollection<UserRoles> collection = db.GetCollection<UserRoles>("userrole");
                    DoUserCollectionInitialization(collection);
                    _userRoleCollection = new DefaultStoreWrapper<UserRoles>(collection);
                }
                return _userRoleCollection;
            }
            set { _userRoleCollection = value; }
        }
        private void DoUserCollectionInitialization(MongoCollection<UserRoles> collection)
        {
            //collection.EnsureIndex(""
        }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            base.Initialize(name, config);
            foreach (string item in config.Keys)
            {
                if (item.ToLower() == "connectionstring")
                {
                    this.ConnectionString = config[item];
                }
            }
        }

    }
}
